nanopyx._version

Git implementation of _version.py.

  1# This file helps to compute a version number in source trees obtained from
  2# git-archive tarball (such as those provided by githubs download-from-tag
  3# feature). Distribution tarballs (built by setup.py sdist) and build
  4# directories (produced by setup.py build) will contain a much shorter file
  5# that just contains the computed version number.
  6
  7# This file is released into the public domain.
  8# Generated by versioneer-0.28
  9# https://github.com/python-versioneer/python-versioneer
 10
 11"""Git implementation of _version.py."""
 12
 13import errno
 14import os
 15import re
 16import subprocess
 17import sys
 18from typing import Callable, Dict
 19import functools
 20
 21
 22def get_keywords():
 23    """Get the keywords needed to look up the version information."""
 24    # these strings will be replaced by git during git-archive.
 25    # setup.py/versioneer.py will grep for the variable names, so they must
 26    # each be defined on a line of their own. _version.py will just call
 27    # get_keywords().
 28    git_refnames = "$Format:%d$"
 29    git_full = "$Format:%H$"
 30    git_date = "$Format:%ci$"
 31    keywords = {"refnames": git_refnames, "full": git_full, "date": git_date}
 32    return keywords
 33
 34
 35class VersioneerConfig:
 36    """Container for Versioneer configuration parameters."""
 37
 38
 39def get_config():
 40    """Create, populate and return the VersioneerConfig() object."""
 41    # these strings are filled in when 'setup.py versioneer' creates
 42    # _version.py
 43    cfg = VersioneerConfig()
 44    cfg.VCS = "git"
 45    cfg.style = "pep440"
 46    cfg.tag_prefix = ""
 47    cfg.parentdir_prefix = "nanopyx-"
 48    cfg.versionfile_source = "src/nanopyx/_version.py"
 49    cfg.verbose = False
 50    return cfg
 51
 52
 53class NotThisMethod(Exception):
 54    """Exception raised if a method is not valid for the current scenario."""
 55
 56
 57LONG_VERSION_PY: Dict[str, str] = {}
 58HANDLERS: Dict[str, Dict[str, Callable]] = {}
 59
 60
 61def register_vcs_handler(vcs, method):  # decorator
 62    """Create decorator to mark a method as the handler of a VCS."""
 63
 64    def decorate(f):
 65        """Store f in HANDLERS[vcs][method]."""
 66        if vcs not in HANDLERS:
 67            HANDLERS[vcs] = {}
 68        HANDLERS[vcs][method] = f
 69        return f
 70
 71    return decorate
 72
 73
 74def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, env=None):
 75    """Call the given command(s)."""
 76    assert isinstance(commands, list)
 77    process = None
 78
 79    popen_kwargs = {}
 80    if sys.platform == "win32":
 81        # This hides the console window if pythonw.exe is used
 82        startupinfo = subprocess.STARTUPINFO()
 83        startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
 84        popen_kwargs["startupinfo"] = startupinfo
 85
 86    for command in commands:
 87        try:
 88            dispcmd = str([command] + args)
 89            # remember shell=False, so use git.cmd on windows, not just git
 90            process = subprocess.Popen(
 91                [command] + args,
 92                cwd=cwd,
 93                env=env,
 94                stdout=subprocess.PIPE,
 95                stderr=(subprocess.PIPE if hide_stderr else None),
 96                **popen_kwargs,
 97            )
 98            break
 99        except OSError:
100            e = sys.exc_info()[1]
101            if e.errno == errno.ENOENT:
102                continue
103            if verbose:
104                print("unable to run %s" % dispcmd)
105                print(e)
106            return None, None
107    else:
108        if verbose:
109            print("unable to find command, tried %s" % (commands,))
110        return None, None
111    stdout = process.communicate()[0].strip().decode()
112    if process.returncode != 0:
113        if verbose:
114            print("unable to run %s (error)" % dispcmd)
115            print("stdout was %s" % stdout)
116        return None, process.returncode
117    return stdout, process.returncode
118
119
120def versions_from_parentdir(parentdir_prefix, root, verbose):
121    """Try to determine the version from the parent directory name.
122
123    Source tarballs conventionally unpack into a directory that includes both
124    the project name and a version string. We will also support searching up
125    two directory levels for an appropriately named parent directory
126    """
127    rootdirs = []
128
129    for _ in range(3):
130        dirname = os.path.basename(root)
131        if dirname.startswith(parentdir_prefix):
132            return {
133                "version": dirname[len(parentdir_prefix) :],
134                "full-revisionid": None,
135                "dirty": False,
136                "error": None,
137                "date": None,
138            }
139        rootdirs.append(root)
140        root = os.path.dirname(root)  # up a level
141
142    if verbose:
143        print(
144            "Tried directories %s but none started with prefix %s"
145            % (str(rootdirs), parentdir_prefix)
146        )
147    raise NotThisMethod("rootdir doesn't start with parentdir_prefix")
148
149
150@register_vcs_handler("git", "get_keywords")
151def git_get_keywords(versionfile_abs):
152    """Extract version information from the given file."""
153    # the code embedded in _version.py can just fetch the value of these
154    # keywords. When used from setup.py, we don't want to import _version.py,
155    # so we do it with a regexp instead. This function is not used from
156    # _version.py.
157    keywords = {}
158    try:
159        with open(versionfile_abs, "r") as fobj:
160            for line in fobj:
161                if line.strip().startswith("git_refnames ="):
162                    mo = re.search(r'=\s*"(.*)"', line)
163                    if mo:
164                        keywords["refnames"] = mo.group(1)
165                if line.strip().startswith("git_full ="):
166                    mo = re.search(r'=\s*"(.*)"', line)
167                    if mo:
168                        keywords["full"] = mo.group(1)
169                if line.strip().startswith("git_date ="):
170                    mo = re.search(r'=\s*"(.*)"', line)
171                    if mo:
172                        keywords["date"] = mo.group(1)
173    except OSError:
174        pass
175    return keywords
176
177
178@register_vcs_handler("git", "keywords")
179def git_versions_from_keywords(keywords, tag_prefix, verbose):
180    """Get version information from git keywords."""
181    if "refnames" not in keywords:
182        raise NotThisMethod("Short version file found")
183    date = keywords.get("date")
184    if date is not None:
185        # Use only the last line.  Previous lines may contain GPG signature
186        # information.
187        date = date.splitlines()[-1]
188
189        # git-2.2.0 added "%cI", which expands to an ISO-8601 -compliant
190        # datestamp. However we prefer "%ci" (which expands to an "ISO-8601
191        # -like" string, which we must then edit to make compliant), because
192        # it's been around since git-1.5.3, and it's too difficult to
193        # discover which version we're using, or to work around using an
194        # older one.
195        date = date.strip().replace(" ", "T", 1).replace(" ", "", 1)
196    refnames = keywords["refnames"].strip()
197    if refnames.startswith("$Format"):
198        if verbose:
199            print("keywords are unexpanded, not using")
200        raise NotThisMethod("unexpanded keywords, not a git-archive tarball")
201    refs = {r.strip() for r in refnames.strip("()").split(",")}
202    # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of
203    # just "foo-1.0". If we see a "tag: " prefix, prefer those.
204    TAG = "tag: "
205    tags = {r[len(TAG) :] for r in refs if r.startswith(TAG)}
206    if not tags:
207        # Either we're using git < 1.8.3, or there really are no tags. We use
208        # a heuristic: assume all version tags have a digit. The old git %d
209        # expansion behaves like git log --decorate=short and strips out the
210        # refs/heads/ and refs/tags/ prefixes that would let us distinguish
211        # between branches and tags. By ignoring refnames without digits, we
212        # filter out many common branch names like "release" and
213        # "stabilization", as well as "HEAD" and "master".
214        tags = {r for r in refs if re.search(r"\d", r)}
215        if verbose:
216            print("discarding '%s', no digits" % ",".join(refs - tags))
217    if verbose:
218        print("likely tags: %s" % ",".join(sorted(tags)))
219    for ref in sorted(tags):
220        # sorting will prefer e.g. "2.0" over "2.0rc1"
221        if ref.startswith(tag_prefix):
222            r = ref[len(tag_prefix) :]
223            # Filter out refs that exactly match prefix or that don't start
224            # with a number once the prefix is stripped (mostly a concern
225            # when prefix is '')
226            if not re.match(r"\d", r):
227                continue
228            if verbose:
229                print("picking %s" % r)
230            return {
231                "version": r,
232                "full-revisionid": keywords["full"].strip(),
233                "dirty": False,
234                "error": None,
235                "date": date,
236            }
237    # no suitable tags, so version is "0+unknown", but full hex is still there
238    if verbose:
239        print("no suitable tags, using unknown + full revision id")
240    return {
241        "version": "0+unknown",
242        "full-revisionid": keywords["full"].strip(),
243        "dirty": False,
244        "error": "no suitable tags",
245        "date": None,
246    }
247
248
249@register_vcs_handler("git", "pieces_from_vcs")
250def git_pieces_from_vcs(tag_prefix, root, verbose, runner=run_command):
251    """Get version from 'git describe' in the root of the source tree.
252
253    This only gets called if the git-archive 'subst' keywords were *not*
254    expanded, and _version.py hasn't already been rewritten with a short
255    version string, meaning we're inside a checked out source tree.
256    """
257    GITS = ["git"]
258    if sys.platform == "win32":
259        GITS = ["git.cmd", "git.exe"]
260
261    # GIT_DIR can interfere with correct operation of Versioneer.
262    # It may be intended to be passed to the Versioneer-versioned project,
263    # but that should not change where we get our version from.
264    env = os.environ.copy()
265    env.pop("GIT_DIR", None)
266    runner = functools.partial(runner, env=env)
267
268    _, rc = runner(GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=not verbose)
269    if rc != 0:
270        if verbose:
271            print("Directory %s not under git control" % root)
272        raise NotThisMethod("'git rev-parse --git-dir' returned error")
273
274    # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty]
275    # if there isn't one, this yields HEX[-dirty] (no NUM)
276    describe_out, rc = runner(
277        GITS,
278        [
279            "describe",
280            "--tags",
281            "--dirty",
282            "--always",
283            "--long",
284            "--match",
285            f"{tag_prefix}[[:digit:]]*",
286        ],
287        cwd=root,
288    )
289    # --long was added in git-1.5.5
290    if describe_out is None:
291        raise NotThisMethod("'git describe' failed")
292    describe_out = describe_out.strip()
293    full_out, rc = runner(GITS, ["rev-parse", "HEAD"], cwd=root)
294    if full_out is None:
295        raise NotThisMethod("'git rev-parse' failed")
296    full_out = full_out.strip()
297
298    pieces = {}
299    pieces["long"] = full_out
300    pieces["short"] = full_out[:7]  # maybe improved later
301    pieces["error"] = None
302
303    branch_name, rc = runner(GITS, ["rev-parse", "--abbrev-ref", "HEAD"], cwd=root)
304    # --abbrev-ref was added in git-1.6.3
305    if rc != 0 or branch_name is None:
306        raise NotThisMethod("'git rev-parse --abbrev-ref' returned error")
307    branch_name = branch_name.strip()
308
309    if branch_name == "HEAD":
310        # If we aren't exactly on a branch, pick a branch which represents
311        # the current commit. If all else fails, we are on a branchless
312        # commit.
313        branches, rc = runner(GITS, ["branch", "--contains"], cwd=root)
314        # --contains was added in git-1.5.4
315        if rc != 0 or branches is None:
316            raise NotThisMethod("'git branch --contains' returned error")
317        branches = branches.split("\n")
318
319        # Remove the first line if we're running detached
320        if "(" in branches[0]:
321            branches.pop(0)
322
323        # Strip off the leading "* " from the list of branches.
324        branches = [branch[2:] for branch in branches]
325        if "master" in branches:
326            branch_name = "master"
327        elif not branches:
328            branch_name = None
329        else:
330            # Pick the first branch that is returned. Good or bad.
331            branch_name = branches[0]
332
333    pieces["branch"] = branch_name
334
335    # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty]
336    # TAG might have hyphens.
337    git_describe = describe_out
338
339    # look for -dirty suffix
340    dirty = git_describe.endswith("-dirty")
341    pieces["dirty"] = dirty
342    if dirty:
343        git_describe = git_describe[: git_describe.rindex("-dirty")]
344
345    # now we have TAG-NUM-gHEX or HEX
346
347    if "-" in git_describe:
348        # TAG-NUM-gHEX
349        mo = re.search(r"^(.+)-(\d+)-g([0-9a-f]+)$", git_describe)
350        if not mo:
351            # unparsable. Maybe git-describe is misbehaving?
352            pieces["error"] = "unable to parse git-describe output: '%s'" % describe_out
353            return pieces
354
355        # tag
356        full_tag = mo.group(1)
357        if not full_tag.startswith(tag_prefix):
358            if verbose:
359                fmt = "tag '%s' doesn't start with prefix '%s'"
360                print(fmt % (full_tag, tag_prefix))
361            pieces["error"] = "tag '%s' doesn't start with prefix '%s'" % (
362                full_tag,
363                tag_prefix,
364            )
365            return pieces
366        pieces["closest-tag"] = full_tag[len(tag_prefix) :]
367
368        # distance: number of commits since tag
369        pieces["distance"] = int(mo.group(2))
370
371        # commit: short hex revision ID
372        pieces["short"] = mo.group(3)
373
374    else:
375        # HEX: no tags
376        pieces["closest-tag"] = None
377        out, rc = runner(GITS, ["rev-list", "HEAD", "--left-right"], cwd=root)
378        pieces["distance"] = len(out.split())  # total number of commits
379
380    # commit date: see ISO-8601 comment in git_versions_from_keywords()
381    date = runner(GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root)[0].strip()
382    # Use only the last line.  Previous lines may contain GPG signature
383    # information.
384    date = date.splitlines()[-1]
385    pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1)
386
387    return pieces
388
389
390def plus_or_dot(pieces):
391    """Return a + if we don't already have one, else return a ."""
392    if "+" in pieces.get("closest-tag", ""):
393        return "."
394    return "+"
395
396
397def render_pep440(pieces):
398    """Build up version string, with post-release "local version identifier".
399
400    Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you
401    get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty
402
403    Exceptions:
404    1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty]
405    """
406    if pieces["closest-tag"]:
407        rendered = pieces["closest-tag"]
408        if pieces["distance"] or pieces["dirty"]:
409            rendered += plus_or_dot(pieces)
410            rendered += "%d.g%s" % (pieces["distance"], pieces["short"])
411            if pieces["dirty"]:
412                rendered += ".dirty"
413    else:
414        # exception #1
415        rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"])
416        if pieces["dirty"]:
417            rendered += ".dirty"
418    return rendered
419
420
421def render_pep440_branch(pieces):
422    """TAG[[.dev0]+DISTANCE.gHEX[.dirty]] .
423
424    The ".dev0" means not master branch. Note that .dev0 sorts backwards
425    (a feature branch will appear "older" than the master branch).
426
427    Exceptions:
428    1: no tags. 0[.dev0]+untagged.DISTANCE.gHEX[.dirty]
429    """
430    if pieces["closest-tag"]:
431        rendered = pieces["closest-tag"]
432        if pieces["distance"] or pieces["dirty"]:
433            if pieces["branch"] != "master":
434                rendered += ".dev0"
435            rendered += plus_or_dot(pieces)
436            rendered += "%d.g%s" % (pieces["distance"], pieces["short"])
437            if pieces["dirty"]:
438                rendered += ".dirty"
439    else:
440        # exception #1
441        rendered = "0"
442        if pieces["branch"] != "master":
443            rendered += ".dev0"
444        rendered += "+untagged.%d.g%s" % (pieces["distance"], pieces["short"])
445        if pieces["dirty"]:
446            rendered += ".dirty"
447    return rendered
448
449
450def pep440_split_post(ver):
451    """Split pep440 version string at the post-release segment.
452
453    Returns the release segments before the post-release and the
454    post-release version number (or -1 if no post-release segment is present).
455    """
456    vc = str.split(ver, ".post")
457    return vc[0], int(vc[1] or 0) if len(vc) == 2 else None
458
459
460def render_pep440_pre(pieces):
461    """TAG[.postN.devDISTANCE] -- No -dirty.
462
463    Exceptions:
464    1: no tags. 0.post0.devDISTANCE
465    """
466    if pieces["closest-tag"]:
467        if pieces["distance"]:
468            # update the post release segment
469            tag_version, post_version = pep440_split_post(pieces["closest-tag"])
470            rendered = tag_version
471            if post_version is not None:
472                rendered += ".post%d.dev%d" % (post_version + 1, pieces["distance"])
473            else:
474                rendered += ".post0.dev%d" % (pieces["distance"])
475        else:
476            # no commits, use the tag as the version
477            rendered = pieces["closest-tag"]
478    else:
479        # exception #1
480        rendered = "0.post0.dev%d" % pieces["distance"]
481    return rendered
482
483
484def render_pep440_post(pieces):
485    """TAG[.postDISTANCE[.dev0]+gHEX] .
486
487    The ".dev0" means dirty. Note that .dev0 sorts backwards
488    (a dirty tree will appear "older" than the corresponding clean one),
489    but you shouldn't be releasing software with -dirty anyways.
490
491    Exceptions:
492    1: no tags. 0.postDISTANCE[.dev0]
493    """
494    if pieces["closest-tag"]:
495        rendered = pieces["closest-tag"]
496        if pieces["distance"] or pieces["dirty"]:
497            rendered += ".post%d" % pieces["distance"]
498            if pieces["dirty"]:
499                rendered += ".dev0"
500            rendered += plus_or_dot(pieces)
501            rendered += "g%s" % pieces["short"]
502    else:
503        # exception #1
504        rendered = "0.post%d" % pieces["distance"]
505        if pieces["dirty"]:
506            rendered += ".dev0"
507        rendered += "+g%s" % pieces["short"]
508    return rendered
509
510
511def render_pep440_post_branch(pieces):
512    """TAG[.postDISTANCE[.dev0]+gHEX[.dirty]] .
513
514    The ".dev0" means not master branch.
515
516    Exceptions:
517    1: no tags. 0.postDISTANCE[.dev0]+gHEX[.dirty]
518    """
519    if pieces["closest-tag"]:
520        rendered = pieces["closest-tag"]
521        if pieces["distance"] or pieces["dirty"]:
522            rendered += ".post%d" % pieces["distance"]
523            if pieces["branch"] != "master":
524                rendered += ".dev0"
525            rendered += plus_or_dot(pieces)
526            rendered += "g%s" % pieces["short"]
527            if pieces["dirty"]:
528                rendered += ".dirty"
529    else:
530        # exception #1
531        rendered = "0.post%d" % pieces["distance"]
532        if pieces["branch"] != "master":
533            rendered += ".dev0"
534        rendered += "+g%s" % pieces["short"]
535        if pieces["dirty"]:
536            rendered += ".dirty"
537    return rendered
538
539
540def render_pep440_old(pieces):
541    """TAG[.postDISTANCE[.dev0]] .
542
543    The ".dev0" means dirty.
544
545    Exceptions:
546    1: no tags. 0.postDISTANCE[.dev0]
547    """
548    if pieces["closest-tag"]:
549        rendered = pieces["closest-tag"]
550        if pieces["distance"] or pieces["dirty"]:
551            rendered += ".post%d" % pieces["distance"]
552            if pieces["dirty"]:
553                rendered += ".dev0"
554    else:
555        # exception #1
556        rendered = "0.post%d" % pieces["distance"]
557        if pieces["dirty"]:
558            rendered += ".dev0"
559    return rendered
560
561
562def render_git_describe(pieces):
563    """TAG[-DISTANCE-gHEX][-dirty].
564
565    Like 'git describe --tags --dirty --always'.
566
567    Exceptions:
568    1: no tags. HEX[-dirty]  (note: no 'g' prefix)
569    """
570    if pieces["closest-tag"]:
571        rendered = pieces["closest-tag"]
572        if pieces["distance"]:
573            rendered += "-%d-g%s" % (pieces["distance"], pieces["short"])
574    else:
575        # exception #1
576        rendered = pieces["short"]
577    if pieces["dirty"]:
578        rendered += "-dirty"
579    return rendered
580
581
582def render_git_describe_long(pieces):
583    """TAG-DISTANCE-gHEX[-dirty].
584
585    Like 'git describe --tags --dirty --always -long'.
586    The distance/hash is unconditional.
587
588    Exceptions:
589    1: no tags. HEX[-dirty]  (note: no 'g' prefix)
590    """
591    if pieces["closest-tag"]:
592        rendered = pieces["closest-tag"]
593        rendered += "-%d-g%s" % (pieces["distance"], pieces["short"])
594    else:
595        # exception #1
596        rendered = pieces["short"]
597    if pieces["dirty"]:
598        rendered += "-dirty"
599    return rendered
600
601
602def render(pieces, style):
603    """Render the given version pieces into the requested style."""
604    if pieces["error"]:
605        return {
606            "version": "unknown",
607            "full-revisionid": pieces.get("long"),
608            "dirty": None,
609            "error": pieces["error"],
610            "date": None,
611        }
612
613    if not style or style == "default":
614        style = "pep440"  # the default
615
616    if style == "pep440":
617        rendered = render_pep440(pieces)
618    elif style == "pep440-branch":
619        rendered = render_pep440_branch(pieces)
620    elif style == "pep440-pre":
621        rendered = render_pep440_pre(pieces)
622    elif style == "pep440-post":
623        rendered = render_pep440_post(pieces)
624    elif style == "pep440-post-branch":
625        rendered = render_pep440_post_branch(pieces)
626    elif style == "pep440-old":
627        rendered = render_pep440_old(pieces)
628    elif style == "git-describe":
629        rendered = render_git_describe(pieces)
630    elif style == "git-describe-long":
631        rendered = render_git_describe_long(pieces)
632    else:
633        raise ValueError("unknown style '%s'" % style)
634
635    return {
636        "version": rendered,
637        "full-revisionid": pieces["long"],
638        "dirty": pieces["dirty"],
639        "error": None,
640        "date": pieces.get("date"),
641    }
642
643
644def get_versions():
645    """Get version information or return default if unable to do so."""
646    # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have
647    # __file__, we can work backwards from there to the root. Some
648    # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which
649    # case we can only use expanded keywords.
650
651    cfg = get_config()
652    verbose = cfg.verbose
653
654    try:
655        return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, verbose)
656    except NotThisMethod:
657        pass
658
659    try:
660        root = os.path.realpath(__file__)
661        # versionfile_source is the relative path from the top of the source
662        # tree (where the .git directory might live) to this file. Invert
663        # this to find the root from __file__.
664        for _ in cfg.versionfile_source.split("/"):
665            root = os.path.dirname(root)
666    except NameError:
667        return {
668            "version": "0+unknown",
669            "full-revisionid": None,
670            "dirty": None,
671            "error": "unable to find root of source tree",
672            "date": None,
673        }
674
675    try:
676        pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose)
677        return render(pieces, cfg.style)
678    except NotThisMethod:
679        pass
680
681    try:
682        if cfg.parentdir_prefix:
683            return versions_from_parentdir(cfg.parentdir_prefix, root, verbose)
684    except NotThisMethod:
685        pass
686
687    return {
688        "version": "0+unknown",
689        "full-revisionid": None,
690        "dirty": None,
691        "error": "unable to compute version",
692        "date": None,
693    }
def get_keywords():
23def get_keywords():
24    """Get the keywords needed to look up the version information."""
25    # these strings will be replaced by git during git-archive.
26    # setup.py/versioneer.py will grep for the variable names, so they must
27    # each be defined on a line of their own. _version.py will just call
28    # get_keywords().
29    git_refnames = "$Format:%d$"
30    git_full = "$Format:%H$"
31    git_date = "$Format:%ci$"
32    keywords = {"refnames": git_refnames, "full": git_full, "date": git_date}
33    return keywords

Get the keywords needed to look up the version information.

class VersioneerConfig:
36class VersioneerConfig:
37    """Container for Versioneer configuration parameters."""

Container for Versioneer configuration parameters.

def get_config():
40def get_config():
41    """Create, populate and return the VersioneerConfig() object."""
42    # these strings are filled in when 'setup.py versioneer' creates
43    # _version.py
44    cfg = VersioneerConfig()
45    cfg.VCS = "git"
46    cfg.style = "pep440"
47    cfg.tag_prefix = ""
48    cfg.parentdir_prefix = "nanopyx-"
49    cfg.versionfile_source = "src/nanopyx/_version.py"
50    cfg.verbose = False
51    return cfg

Create, populate and return the VersioneerConfig() object.

class NotThisMethod(builtins.Exception):
54class NotThisMethod(Exception):
55    """Exception raised if a method is not valid for the current scenario."""

Exception raised if a method is not valid for the current scenario.

Inherited Members
builtins.Exception
Exception
builtins.BaseException
with_traceback
args
LONG_VERSION_PY: Dict[str, str] = {}
HANDLERS: Dict[str, Dict[str, Callable]] = {'git': {'get_keywords': <function git_get_keywords>, 'keywords': <function git_versions_from_keywords>, 'pieces_from_vcs': <function git_pieces_from_vcs>}}
def register_vcs_handler(vcs, method):
62def register_vcs_handler(vcs, method):  # decorator
63    """Create decorator to mark a method as the handler of a VCS."""
64
65    def decorate(f):
66        """Store f in HANDLERS[vcs][method]."""
67        if vcs not in HANDLERS:
68            HANDLERS[vcs] = {}
69        HANDLERS[vcs][method] = f
70        return f
71
72    return decorate

Create decorator to mark a method as the handler of a VCS.

def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, env=None):
 75def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, env=None):
 76    """Call the given command(s)."""
 77    assert isinstance(commands, list)
 78    process = None
 79
 80    popen_kwargs = {}
 81    if sys.platform == "win32":
 82        # This hides the console window if pythonw.exe is used
 83        startupinfo = subprocess.STARTUPINFO()
 84        startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
 85        popen_kwargs["startupinfo"] = startupinfo
 86
 87    for command in commands:
 88        try:
 89            dispcmd = str([command] + args)
 90            # remember shell=False, so use git.cmd on windows, not just git
 91            process = subprocess.Popen(
 92                [command] + args,
 93                cwd=cwd,
 94                env=env,
 95                stdout=subprocess.PIPE,
 96                stderr=(subprocess.PIPE if hide_stderr else None),
 97                **popen_kwargs,
 98            )
 99            break
100        except OSError:
101            e = sys.exc_info()[1]
102            if e.errno == errno.ENOENT:
103                continue
104            if verbose:
105                print("unable to run %s" % dispcmd)
106                print(e)
107            return None, None
108    else:
109        if verbose:
110            print("unable to find command, tried %s" % (commands,))
111        return None, None
112    stdout = process.communicate()[0].strip().decode()
113    if process.returncode != 0:
114        if verbose:
115            print("unable to run %s (error)" % dispcmd)
116            print("stdout was %s" % stdout)
117        return None, process.returncode
118    return stdout, process.returncode

Call the given command(s).

def versions_from_parentdir(parentdir_prefix, root, verbose):
121def versions_from_parentdir(parentdir_prefix, root, verbose):
122    """Try to determine the version from the parent directory name.
123
124    Source tarballs conventionally unpack into a directory that includes both
125    the project name and a version string. We will also support searching up
126    two directory levels for an appropriately named parent directory
127    """
128    rootdirs = []
129
130    for _ in range(3):
131        dirname = os.path.basename(root)
132        if dirname.startswith(parentdir_prefix):
133            return {
134                "version": dirname[len(parentdir_prefix) :],
135                "full-revisionid": None,
136                "dirty": False,
137                "error": None,
138                "date": None,
139            }
140        rootdirs.append(root)
141        root = os.path.dirname(root)  # up a level
142
143    if verbose:
144        print(
145            "Tried directories %s but none started with prefix %s"
146            % (str(rootdirs), parentdir_prefix)
147        )
148    raise NotThisMethod("rootdir doesn't start with parentdir_prefix")

Try to determine the version from the parent directory name.

Source tarballs conventionally unpack into a directory that includes both the project name and a version string. We will also support searching up two directory levels for an appropriately named parent directory

@register_vcs_handler('git', 'get_keywords')
def git_get_keywords(versionfile_abs):
151@register_vcs_handler("git", "get_keywords")
152def git_get_keywords(versionfile_abs):
153    """Extract version information from the given file."""
154    # the code embedded in _version.py can just fetch the value of these
155    # keywords. When used from setup.py, we don't want to import _version.py,
156    # so we do it with a regexp instead. This function is not used from
157    # _version.py.
158    keywords = {}
159    try:
160        with open(versionfile_abs, "r") as fobj:
161            for line in fobj:
162                if line.strip().startswith("git_refnames ="):
163                    mo = re.search(r'=\s*"(.*)"', line)
164                    if mo:
165                        keywords["refnames"] = mo.group(1)
166                if line.strip().startswith("git_full ="):
167                    mo = re.search(r'=\s*"(.*)"', line)
168                    if mo:
169                        keywords["full"] = mo.group(1)
170                if line.strip().startswith("git_date ="):
171                    mo = re.search(r'=\s*"(.*)"', line)
172                    if mo:
173                        keywords["date"] = mo.group(1)
174    except OSError:
175        pass
176    return keywords

Extract version information from the given file.

@register_vcs_handler('git', 'keywords')
def git_versions_from_keywords(keywords, tag_prefix, verbose):
179@register_vcs_handler("git", "keywords")
180def git_versions_from_keywords(keywords, tag_prefix, verbose):
181    """Get version information from git keywords."""
182    if "refnames" not in keywords:
183        raise NotThisMethod("Short version file found")
184    date = keywords.get("date")
185    if date is not None:
186        # Use only the last line.  Previous lines may contain GPG signature
187        # information.
188        date = date.splitlines()[-1]
189
190        # git-2.2.0 added "%cI", which expands to an ISO-8601 -compliant
191        # datestamp. However we prefer "%ci" (which expands to an "ISO-8601
192        # -like" string, which we must then edit to make compliant), because
193        # it's been around since git-1.5.3, and it's too difficult to
194        # discover which version we're using, or to work around using an
195        # older one.
196        date = date.strip().replace(" ", "T", 1).replace(" ", "", 1)
197    refnames = keywords["refnames"].strip()
198    if refnames.startswith("$Format"):
199        if verbose:
200            print("keywords are unexpanded, not using")
201        raise NotThisMethod("unexpanded keywords, not a git-archive tarball")
202    refs = {r.strip() for r in refnames.strip("()").split(",")}
203    # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of
204    # just "foo-1.0". If we see a "tag: " prefix, prefer those.
205    TAG = "tag: "
206    tags = {r[len(TAG) :] for r in refs if r.startswith(TAG)}
207    if not tags:
208        # Either we're using git < 1.8.3, or there really are no tags. We use
209        # a heuristic: assume all version tags have a digit. The old git %d
210        # expansion behaves like git log --decorate=short and strips out the
211        # refs/heads/ and refs/tags/ prefixes that would let us distinguish
212        # between branches and tags. By ignoring refnames without digits, we
213        # filter out many common branch names like "release" and
214        # "stabilization", as well as "HEAD" and "master".
215        tags = {r for r in refs if re.search(r"\d", r)}
216        if verbose:
217            print("discarding '%s', no digits" % ",".join(refs - tags))
218    if verbose:
219        print("likely tags: %s" % ",".join(sorted(tags)))
220    for ref in sorted(tags):
221        # sorting will prefer e.g. "2.0" over "2.0rc1"
222        if ref.startswith(tag_prefix):
223            r = ref[len(tag_prefix) :]
224            # Filter out refs that exactly match prefix or that don't start
225            # with a number once the prefix is stripped (mostly a concern
226            # when prefix is '')
227            if not re.match(r"\d", r):
228                continue
229            if verbose:
230                print("picking %s" % r)
231            return {
232                "version": r,
233                "full-revisionid": keywords["full"].strip(),
234                "dirty": False,
235                "error": None,
236                "date": date,
237            }
238    # no suitable tags, so version is "0+unknown", but full hex is still there
239    if verbose:
240        print("no suitable tags, using unknown + full revision id")
241    return {
242        "version": "0+unknown",
243        "full-revisionid": keywords["full"].strip(),
244        "dirty": False,
245        "error": "no suitable tags",
246        "date": None,
247    }

Get version information from git keywords.

@register_vcs_handler('git', 'pieces_from_vcs')
def git_pieces_from_vcs(tag_prefix, root, verbose, runner=<function run_command>):
250@register_vcs_handler("git", "pieces_from_vcs")
251def git_pieces_from_vcs(tag_prefix, root, verbose, runner=run_command):
252    """Get version from 'git describe' in the root of the source tree.
253
254    This only gets called if the git-archive 'subst' keywords were *not*
255    expanded, and _version.py hasn't already been rewritten with a short
256    version string, meaning we're inside a checked out source tree.
257    """
258    GITS = ["git"]
259    if sys.platform == "win32":
260        GITS = ["git.cmd", "git.exe"]
261
262    # GIT_DIR can interfere with correct operation of Versioneer.
263    # It may be intended to be passed to the Versioneer-versioned project,
264    # but that should not change where we get our version from.
265    env = os.environ.copy()
266    env.pop("GIT_DIR", None)
267    runner = functools.partial(runner, env=env)
268
269    _, rc = runner(GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=not verbose)
270    if rc != 0:
271        if verbose:
272            print("Directory %s not under git control" % root)
273        raise NotThisMethod("'git rev-parse --git-dir' returned error")
274
275    # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty]
276    # if there isn't one, this yields HEX[-dirty] (no NUM)
277    describe_out, rc = runner(
278        GITS,
279        [
280            "describe",
281            "--tags",
282            "--dirty",
283            "--always",
284            "--long",
285            "--match",
286            f"{tag_prefix}[[:digit:]]*",
287        ],
288        cwd=root,
289    )
290    # --long was added in git-1.5.5
291    if describe_out is None:
292        raise NotThisMethod("'git describe' failed")
293    describe_out = describe_out.strip()
294    full_out, rc = runner(GITS, ["rev-parse", "HEAD"], cwd=root)
295    if full_out is None:
296        raise NotThisMethod("'git rev-parse' failed")
297    full_out = full_out.strip()
298
299    pieces = {}
300    pieces["long"] = full_out
301    pieces["short"] = full_out[:7]  # maybe improved later
302    pieces["error"] = None
303
304    branch_name, rc = runner(GITS, ["rev-parse", "--abbrev-ref", "HEAD"], cwd=root)
305    # --abbrev-ref was added in git-1.6.3
306    if rc != 0 or branch_name is None:
307        raise NotThisMethod("'git rev-parse --abbrev-ref' returned error")
308    branch_name = branch_name.strip()
309
310    if branch_name == "HEAD":
311        # If we aren't exactly on a branch, pick a branch which represents
312        # the current commit. If all else fails, we are on a branchless
313        # commit.
314        branches, rc = runner(GITS, ["branch", "--contains"], cwd=root)
315        # --contains was added in git-1.5.4
316        if rc != 0 or branches is None:
317            raise NotThisMethod("'git branch --contains' returned error")
318        branches = branches.split("\n")
319
320        # Remove the first line if we're running detached
321        if "(" in branches[0]:
322            branches.pop(0)
323
324        # Strip off the leading "* " from the list of branches.
325        branches = [branch[2:] for branch in branches]
326        if "master" in branches:
327            branch_name = "master"
328        elif not branches:
329            branch_name = None
330        else:
331            # Pick the first branch that is returned. Good or bad.
332            branch_name = branches[0]
333
334    pieces["branch"] = branch_name
335
336    # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty]
337    # TAG might have hyphens.
338    git_describe = describe_out
339
340    # look for -dirty suffix
341    dirty = git_describe.endswith("-dirty")
342    pieces["dirty"] = dirty
343    if dirty:
344        git_describe = git_describe[: git_describe.rindex("-dirty")]
345
346    # now we have TAG-NUM-gHEX or HEX
347
348    if "-" in git_describe:
349        # TAG-NUM-gHEX
350        mo = re.search(r"^(.+)-(\d+)-g([0-9a-f]+)$", git_describe)
351        if not mo:
352            # unparsable. Maybe git-describe is misbehaving?
353            pieces["error"] = "unable to parse git-describe output: '%s'" % describe_out
354            return pieces
355
356        # tag
357        full_tag = mo.group(1)
358        if not full_tag.startswith(tag_prefix):
359            if verbose:
360                fmt = "tag '%s' doesn't start with prefix '%s'"
361                print(fmt % (full_tag, tag_prefix))
362            pieces["error"] = "tag '%s' doesn't start with prefix '%s'" % (
363                full_tag,
364                tag_prefix,
365            )
366            return pieces
367        pieces["closest-tag"] = full_tag[len(tag_prefix) :]
368
369        # distance: number of commits since tag
370        pieces["distance"] = int(mo.group(2))
371
372        # commit: short hex revision ID
373        pieces["short"] = mo.group(3)
374
375    else:
376        # HEX: no tags
377        pieces["closest-tag"] = None
378        out, rc = runner(GITS, ["rev-list", "HEAD", "--left-right"], cwd=root)
379        pieces["distance"] = len(out.split())  # total number of commits
380
381    # commit date: see ISO-8601 comment in git_versions_from_keywords()
382    date = runner(GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root)[0].strip()
383    # Use only the last line.  Previous lines may contain GPG signature
384    # information.
385    date = date.splitlines()[-1]
386    pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1)
387
388    return pieces

Get version from 'git describe' in the root of the source tree.

This only gets called if the git-archive 'subst' keywords were not expanded, and _version.py hasn't already been rewritten with a short version string, meaning we're inside a checked out source tree.

def plus_or_dot(pieces):
391def plus_or_dot(pieces):
392    """Return a + if we don't already have one, else return a ."""
393    if "+" in pieces.get("closest-tag", ""):
394        return "."
395    return "+"

Return a + if we don't already have one, else return a .

def render_pep440(pieces):
398def render_pep440(pieces):
399    """Build up version string, with post-release "local version identifier".
400
401    Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you
402    get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty
403
404    Exceptions:
405    1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty]
406    """
407    if pieces["closest-tag"]:
408        rendered = pieces["closest-tag"]
409        if pieces["distance"] or pieces["dirty"]:
410            rendered += plus_or_dot(pieces)
411            rendered += "%d.g%s" % (pieces["distance"], pieces["short"])
412            if pieces["dirty"]:
413                rendered += ".dirty"
414    else:
415        # exception #1
416        rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"])
417        if pieces["dirty"]:
418            rendered += ".dirty"
419    return rendered

Build up version string, with post-release "local version identifier".

Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty

Exceptions: 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty]

def render_pep440_branch(pieces):
422def render_pep440_branch(pieces):
423    """TAG[[.dev0]+DISTANCE.gHEX[.dirty]] .
424
425    The ".dev0" means not master branch. Note that .dev0 sorts backwards
426    (a feature branch will appear "older" than the master branch).
427
428    Exceptions:
429    1: no tags. 0[.dev0]+untagged.DISTANCE.gHEX[.dirty]
430    """
431    if pieces["closest-tag"]:
432        rendered = pieces["closest-tag"]
433        if pieces["distance"] or pieces["dirty"]:
434            if pieces["branch"] != "master":
435                rendered += ".dev0"
436            rendered += plus_or_dot(pieces)
437            rendered += "%d.g%s" % (pieces["distance"], pieces["short"])
438            if pieces["dirty"]:
439                rendered += ".dirty"
440    else:
441        # exception #1
442        rendered = "0"
443        if pieces["branch"] != "master":
444            rendered += ".dev0"
445        rendered += "+untagged.%d.g%s" % (pieces["distance"], pieces["short"])
446        if pieces["dirty"]:
447            rendered += ".dirty"
448    return rendered

TAG[[.dev0]+DISTANCE.gHEX[.dirty]] .

The ".dev0" means not master branch. Note that .dev0 sorts backwards (a feature branch will appear "older" than the master branch).

Exceptions: 1: no tags. 0[.dev0]+untagged.DISTANCE.gHEX[.dirty]

def pep440_split_post(ver):
451def pep440_split_post(ver):
452    """Split pep440 version string at the post-release segment.
453
454    Returns the release segments before the post-release and the
455    post-release version number (or -1 if no post-release segment is present).
456    """
457    vc = str.split(ver, ".post")
458    return vc[0], int(vc[1] or 0) if len(vc) == 2 else None

Split pep440 version string at the post-release segment.

Returns the release segments before the post-release and the post-release version number (or -1 if no post-release segment is present).

def render_pep440_pre(pieces):
461def render_pep440_pre(pieces):
462    """TAG[.postN.devDISTANCE] -- No -dirty.
463
464    Exceptions:
465    1: no tags. 0.post0.devDISTANCE
466    """
467    if pieces["closest-tag"]:
468        if pieces["distance"]:
469            # update the post release segment
470            tag_version, post_version = pep440_split_post(pieces["closest-tag"])
471            rendered = tag_version
472            if post_version is not None:
473                rendered += ".post%d.dev%d" % (post_version + 1, pieces["distance"])
474            else:
475                rendered += ".post0.dev%d" % (pieces["distance"])
476        else:
477            # no commits, use the tag as the version
478            rendered = pieces["closest-tag"]
479    else:
480        # exception #1
481        rendered = "0.post0.dev%d" % pieces["distance"]
482    return rendered

TAG[.postN.devDISTANCE] -- No -dirty.

Exceptions: 1: no tags. 0.post0.devDISTANCE

def render_pep440_post(pieces):
485def render_pep440_post(pieces):
486    """TAG[.postDISTANCE[.dev0]+gHEX] .
487
488    The ".dev0" means dirty. Note that .dev0 sorts backwards
489    (a dirty tree will appear "older" than the corresponding clean one),
490    but you shouldn't be releasing software with -dirty anyways.
491
492    Exceptions:
493    1: no tags. 0.postDISTANCE[.dev0]
494    """
495    if pieces["closest-tag"]:
496        rendered = pieces["closest-tag"]
497        if pieces["distance"] or pieces["dirty"]:
498            rendered += ".post%d" % pieces["distance"]
499            if pieces["dirty"]:
500                rendered += ".dev0"
501            rendered += plus_or_dot(pieces)
502            rendered += "g%s" % pieces["short"]
503    else:
504        # exception #1
505        rendered = "0.post%d" % pieces["distance"]
506        if pieces["dirty"]:
507            rendered += ".dev0"
508        rendered += "+g%s" % pieces["short"]
509    return rendered

TAG[.postDISTANCE[.dev0]+gHEX] .

The ".dev0" means dirty. Note that .dev0 sorts backwards (a dirty tree will appear "older" than the corresponding clean one), but you shouldn't be releasing software with -dirty anyways.

Exceptions: 1: no tags. 0.postDISTANCE[.dev0]

def render_pep440_post_branch(pieces):
512def render_pep440_post_branch(pieces):
513    """TAG[.postDISTANCE[.dev0]+gHEX[.dirty]] .
514
515    The ".dev0" means not master branch.
516
517    Exceptions:
518    1: no tags. 0.postDISTANCE[.dev0]+gHEX[.dirty]
519    """
520    if pieces["closest-tag"]:
521        rendered = pieces["closest-tag"]
522        if pieces["distance"] or pieces["dirty"]:
523            rendered += ".post%d" % pieces["distance"]
524            if pieces["branch"] != "master":
525                rendered += ".dev0"
526            rendered += plus_or_dot(pieces)
527            rendered += "g%s" % pieces["short"]
528            if pieces["dirty"]:
529                rendered += ".dirty"
530    else:
531        # exception #1
532        rendered = "0.post%d" % pieces["distance"]
533        if pieces["branch"] != "master":
534            rendered += ".dev0"
535        rendered += "+g%s" % pieces["short"]
536        if pieces["dirty"]:
537            rendered += ".dirty"
538    return rendered

TAG[.postDISTANCE[.dev0]+gHEX[.dirty]] .

The ".dev0" means not master branch.

Exceptions: 1: no tags. 0.postDISTANCE[.dev0]+gHEX[.dirty]

def render_pep440_old(pieces):
541def render_pep440_old(pieces):
542    """TAG[.postDISTANCE[.dev0]] .
543
544    The ".dev0" means dirty.
545
546    Exceptions:
547    1: no tags. 0.postDISTANCE[.dev0]
548    """
549    if pieces["closest-tag"]:
550        rendered = pieces["closest-tag"]
551        if pieces["distance"] or pieces["dirty"]:
552            rendered += ".post%d" % pieces["distance"]
553            if pieces["dirty"]:
554                rendered += ".dev0"
555    else:
556        # exception #1
557        rendered = "0.post%d" % pieces["distance"]
558        if pieces["dirty"]:
559            rendered += ".dev0"
560    return rendered

TAG[.postDISTANCE[.dev0]] .

The ".dev0" means dirty.

Exceptions: 1: no tags. 0.postDISTANCE[.dev0]

def render_git_describe(pieces):
563def render_git_describe(pieces):
564    """TAG[-DISTANCE-gHEX][-dirty].
565
566    Like 'git describe --tags --dirty --always'.
567
568    Exceptions:
569    1: no tags. HEX[-dirty]  (note: no 'g' prefix)
570    """
571    if pieces["closest-tag"]:
572        rendered = pieces["closest-tag"]
573        if pieces["distance"]:
574            rendered += "-%d-g%s" % (pieces["distance"], pieces["short"])
575    else:
576        # exception #1
577        rendered = pieces["short"]
578    if pieces["dirty"]:
579        rendered += "-dirty"
580    return rendered

TAG[-DISTANCE-gHEX][-dirty].

Like 'git describe --tags --dirty --always'.

Exceptions: 1: no tags. HEX[-dirty] (note: no 'g' prefix)

def render_git_describe_long(pieces):
583def render_git_describe_long(pieces):
584    """TAG-DISTANCE-gHEX[-dirty].
585
586    Like 'git describe --tags --dirty --always -long'.
587    The distance/hash is unconditional.
588
589    Exceptions:
590    1: no tags. HEX[-dirty]  (note: no 'g' prefix)
591    """
592    if pieces["closest-tag"]:
593        rendered = pieces["closest-tag"]
594        rendered += "-%d-g%s" % (pieces["distance"], pieces["short"])
595    else:
596        # exception #1
597        rendered = pieces["short"]
598    if pieces["dirty"]:
599        rendered += "-dirty"
600    return rendered

TAG-DISTANCE-gHEX[-dirty].

Like 'git describe --tags --dirty --always -long'. The distance/hash is unconditional.

Exceptions: 1: no tags. HEX[-dirty] (note: no 'g' prefix)

def render(pieces, style):
603def render(pieces, style):
604    """Render the given version pieces into the requested style."""
605    if pieces["error"]:
606        return {
607            "version": "unknown",
608            "full-revisionid": pieces.get("long"),
609            "dirty": None,
610            "error": pieces["error"],
611            "date": None,
612        }
613
614    if not style or style == "default":
615        style = "pep440"  # the default
616
617    if style == "pep440":
618        rendered = render_pep440(pieces)
619    elif style == "pep440-branch":
620        rendered = render_pep440_branch(pieces)
621    elif style == "pep440-pre":
622        rendered = render_pep440_pre(pieces)
623    elif style == "pep440-post":
624        rendered = render_pep440_post(pieces)
625    elif style == "pep440-post-branch":
626        rendered = render_pep440_post_branch(pieces)
627    elif style == "pep440-old":
628        rendered = render_pep440_old(pieces)
629    elif style == "git-describe":
630        rendered = render_git_describe(pieces)
631    elif style == "git-describe-long":
632        rendered = render_git_describe_long(pieces)
633    else:
634        raise ValueError("unknown style '%s'" % style)
635
636    return {
637        "version": rendered,
638        "full-revisionid": pieces["long"],
639        "dirty": pieces["dirty"],
640        "error": None,
641        "date": pieces.get("date"),
642    }

Render the given version pieces into the requested style.

def get_versions():
645def get_versions():
646    """Get version information or return default if unable to do so."""
647    # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have
648    # __file__, we can work backwards from there to the root. Some
649    # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which
650    # case we can only use expanded keywords.
651
652    cfg = get_config()
653    verbose = cfg.verbose
654
655    try:
656        return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, verbose)
657    except NotThisMethod:
658        pass
659
660    try:
661        root = os.path.realpath(__file__)
662        # versionfile_source is the relative path from the top of the source
663        # tree (where the .git directory might live) to this file. Invert
664        # this to find the root from __file__.
665        for _ in cfg.versionfile_source.split("/"):
666            root = os.path.dirname(root)
667    except NameError:
668        return {
669            "version": "0+unknown",
670            "full-revisionid": None,
671            "dirty": None,
672            "error": "unable to find root of source tree",
673            "date": None,
674        }
675
676    try:
677        pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose)
678        return render(pieces, cfg.style)
679    except NotThisMethod:
680        pass
681
682    try:
683        if cfg.parentdir_prefix:
684            return versions_from_parentdir(cfg.parentdir_prefix, root, verbose)
685    except NotThisMethod:
686        pass
687
688    return {
689        "version": "0+unknown",
690        "full-revisionid": None,
691        "dirty": None,
692        "error": "unable to compute version",
693        "date": None,
694    }

Get version information or return default if unable to do so.